#include <mcp/json/value.h>
#include <mcp/error.h>
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <unordered_map>

namespace mcp {
namespace json {

// Helper function to convert cJSON to Value
static Value cJSON_to_value(cJSON* json, bool take_ownership) __attribute__((unused));
static Value cJSON_to_value(cJSON* json, bool take_ownership) {
    if (!json) {
        return Value();
    }

    if (take_ownership) {
        return Value(json, true);
    } else {
        // Create a copy if we don't take ownership
        cJSON* copy = cJSON_Duplicate(json, true);
        return Value(copy, true);
    }
}

// Helper function to convert Value to cJSON
static cJSON* value_to_cJSON(const Value& value) {
    switch (value.type()) {
        case ValueType::Null:
            return cJSON_CreateNull();
        case ValueType::Boolean:
            return cJSON_CreateBool(value.as_bool());
        case ValueType::Number:
            return cJSON_CreateNumber(value.as_double());
        case ValueType::String:
            return cJSON_CreateString(value.as_string().c_str());
        case ValueType::Array: {
            cJSON* array = cJSON_CreateArray();
            for (const auto& item : value.as_array()) {
                cJSON_AddItemToArray(array, value_to_cJSON(item));
            }
            return array;
        }
        case ValueType::Object: {
            cJSON* object = cJSON_CreateObject();
            for (auto it = value.as_object().begin(); it != value.as_object().end(); ++it) {
        const auto& key = it->first;
        const auto& val = it->second;
        cJSON_AddItemToObject(object, key.c_str(), value_to_cJSON(val));
    }
            return object;
        }
        default:
            return cJSON_CreateNull();
    }
}

// Constructors
Value::Value() noexcept : cJSON_(cJSON_CreateNull()), is_owner_(true) {}

Value::Value(bool b) noexcept : cJSON_(cJSON_CreateBool(b)), is_owner_(true) {}

Value::Value(double n) noexcept : cJSON_(cJSON_CreateNumber(n)), is_owner_(true) {}

Value::Value(int64_t n) noexcept : cJSON_(cJSON_CreateNumber(static_cast<double>(n))), is_owner_(true) {}

Value::Value(const std::string& s) : cJSON_(cJSON_CreateString(s.c_str())), is_owner_(true) {}

Value::Value(std::string&& s) noexcept : cJSON_(cJSON_CreateString(s.c_str())), is_owner_(true) {}

Value::Value(const char* s) : cJSON_(cJSON_CreateString(s)), is_owner_(true) {}

Value::Value(std::vector<Value> array) noexcept : cJSON_(cJSON_CreateArray()), is_owner_(true) {
    for (auto& item : array) {
        cJSON_AddItemToArray(cJSON_, value_to_cJSON(item));
    }
}

Value::Value(std::map<std::string, Value> object) noexcept : cJSON_(cJSON_CreateObject()), is_owner_(true) {
    for (auto it = object.begin(); it != object.end(); ++it) {
        const auto& key = it->first;
        const auto& value = it->second;
        cJSON_AddItemToObject(cJSON_, key.c_str(), value_to_cJSON(value));
    }
}

// Internal constructor for cJSON wrapping
Value::Value(cJSON* json, bool take_ownership) noexcept : cJSON_(json), is_owner_(take_ownership) {}

// Copy and move
Value::Value(const Value& other) : cJSON_(other.cJSON_ ? cJSON_Duplicate(other.cJSON_, true) : nullptr), is_owner_(true) {}

Value::Value(Value&& other) noexcept : cJSON_(other.cJSON_), is_owner_(other.is_owner_) {
    other.cJSON_ = nullptr;
    other.is_owner_ = false;
}

Value& Value::operator=(const Value& other) {
    if (this != &other) {
        if (is_owner_ && cJSON_) {
            cJSON_Delete(cJSON_);
        }
        cJSON_ = other.cJSON_ ? cJSON_Duplicate(other.cJSON_, true) : nullptr;
        is_owner_ = true;
    }
    return *this;
}

Value& Value::operator=(Value&& other) noexcept {
    if (this != &other) {
        if (is_owner_ && cJSON_) {
            cJSON_Delete(cJSON_);
        }
        cJSON_ = other.cJSON_;
        is_owner_ = other.is_owner_;
        other.cJSON_ = nullptr;
        other.is_owner_ = false;
    }
    return *this;
}

// Destructor
Value::~Value() {
    if (is_owner_ && cJSON_) {
        cJSON_Delete(cJSON_);
    }
}

// Type information
ValueType Value::type() const noexcept {
    if (!cJSON_) return ValueType::Null;

    switch (cJSON_->type) {
        case cJSON_NULL: return ValueType::Null;
        case cJSON_True:
        case cJSON_False: return ValueType::Boolean;
        case cJSON_Number: return ValueType::Number;
        case cJSON_String: return ValueType::String;
        case cJSON_Array: return ValueType::Array;
        case cJSON_Object: return ValueType::Object;
        default: return ValueType::Null;
    }
}

// Value accessors
bool Value::as_bool() const {
    if (!cJSON_) return false;
    return cJSON_IsBool(cJSON_) ? cJSON_IsTrue(cJSON_) : false;
}

double Value::as_double() const {
    if (!cJSON_) return 0.0;
    return cJSON_IsNumber(cJSON_) ? cJSON_->valuedouble : 0.0;
}

int64_t Value::as_int64() const {
    if (!cJSON_) return 0;
    return cJSON_IsNumber(cJSON_) ? static_cast<int64_t>(cJSON_->valueint) : 0;
}

const std::string& Value::as_string() const {
    if (!cJSON_ || !cJSON_IsString(cJSON_)) {
        static const std::string empty = "";
        return empty;
    }
    // Note: This creates a copy and stores it statically - not thread safe
    static std::string temp;
    temp = cJSON_->valuestring;
    return temp;
}

const std::vector<Value>& Value::as_array() const {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        static const std::vector<Value> empty;
        return empty;
    }
    // Convert cJSON array to vector
    static std::vector<Value> temp;
    temp.clear();
    cJSON* item = cJSON_->child;
    while (item) {
        temp.emplace_back(item, false);
        item = item->next;
    }
    return temp;
}

const std::map<std::string, Value>& Value::as_object() const {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) {
        static const std::map<std::string, Value> empty;
        return empty;
    }
    // Convert cJSON object to map
    static std::map<std::string, Value> temp;
    temp.clear();
    cJSON* item = cJSON_->child;
    while (item) {
        if (item->string) {
            temp[item->string] = Value(item, false);
        }
        item = item->next;
    }
    return temp;
}

// Modifiers
std::vector<Value>& Value::as_array() {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateArray();
        is_owner_ = true;
    }
    // Note: This creates a copy and returns reference to static - not ideal
    static std::vector<Value> temp;
    temp.clear();
    cJSON* item = cJSON_->child;
    while (item) {
        temp.emplace_back(item, false);
        item = item->next;
    }

    // Clear the array and rebuild from temp
    cJSON_Delete(cJSON_);
    cJSON_ = cJSON_CreateArray();
    for (auto& val : temp) {
        cJSON_AddItemToArray(cJSON_, value_to_cJSON(val));
    }

    return temp;
}

std::map<std::string, Value>& Value::as_object() {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateObject();
        is_owner_ = true;
    }
    // Note: This creates a copy and returns reference to static - not ideal
    static std::map<std::string, Value> temp;
    temp.clear();
    cJSON* item = cJSON_->child;
    while (item) {
        if (item->string) {
            temp[item->string] = Value(item, false);
        }
        item = item->next;
    }

    // Clear the object and rebuild from temp
    cJSON_Delete(cJSON_);
    cJSON_ = cJSON_CreateObject();
    for (auto it = temp.begin(); it != temp.end(); ++it) {
        const auto& key = it->first;
        const auto& val = it->second;
        cJSON_AddItemToObject(cJSON_, key.c_str(), value_to_cJSON(val));
    }

    return temp;
}

// Array access
size_t Value::size() const {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) return 0;
    return cJSON_GetArraySize(cJSON_);
}

bool Value::empty() const {
    return size() == 0;
}

Value& Value::operator[](size_t index) {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateArray();
        is_owner_ = true;
    }

    // Ensure the array has enough elements
    while (static_cast<size_t>(cJSON_GetArraySize(cJSON_)) <= index) {
        cJSON_AddItemToArray(cJSON_, cJSON_CreateNull());
    }

    cJSON* item = cJSON_GetArrayItem(cJSON_, index);
    static Value temp(item, false);
    return temp;
}

const Value& Value::operator[](size_t index) const {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        static const Value empty;
        return empty;
    }

    cJSON* item = cJSON_GetArrayItem(cJSON_, index);
    if (!item) {
        static const Value empty;
        return empty;
    }

    static Value temp(item, false);
    return temp;
}

void Value::push_back(Value value) {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateArray();
        is_owner_ = true;
    }
    cJSON_AddItemToArray(cJSON_, value_to_cJSON(value));
}

void Value::resize(size_t size) {
    if (!cJSON_ || !cJSON_IsArray(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateArray();
        is_owner_ = true;
    }

    size_t current_size = cJSON_GetArraySize(cJSON_);
    if (size > current_size) {
        while (static_cast<size_t>(cJSON_GetArraySize(cJSON_)) < size) {
            cJSON_AddItemToArray(cJSON_, cJSON_CreateNull());
        }
    } else if (size < current_size) {
        // Remove extra elements
        for (size_t i = size; i < current_size; ++i) {
            cJSON_DeleteItemFromArray(cJSON_, i);
        }
    }
}

// Object access
Value& Value::operator[](const std::string& key) {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) {
        if (is_owner_ && cJSON_) cJSON_Delete(cJSON_);
        cJSON_ = cJSON_CreateObject();
        is_owner_ = true;
    }

    cJSON* item = cJSON_GetObjectItem(cJSON_, key.c_str());
    if (!item) {
        cJSON_AddItemToObject(cJSON_, key.c_str(), cJSON_CreateNull());
        item = cJSON_GetObjectItem(cJSON_, key.c_str());
    }

    static Value temp(item, false);
    return temp;
}

Value& Value::operator[](const char* key) {
    return operator[](std::string(key));
}

const Value& Value::operator[](const std::string& key) const {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) {
        static const Value empty;
        return empty;
    }

    cJSON* item = cJSON_GetObjectItem(cJSON_, key.c_str());
    if (!item) {
        static const Value empty;
        return empty;
    }

    static Value temp(item, false);
    return temp;
}

const Value& Value::operator[](const char* key) const {
    return operator[](std::string(key));
}

bool Value::contains(const std::string& key) const {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) return false;
    return cJSON_HasObjectItem(cJSON_, key.c_str());
}

size_t Value::erase(const std::string& key) {
    if (!cJSON_ || !cJSON_IsObject(cJSON_)) return 0;
    if (cJSON_HasObjectItem(cJSON_, key.c_str())) {
        cJSON_DeleteItemFromObject(cJSON_, key.c_str());
        return 1;
    }
    return 0;
}

// Parsing and serialization
expected<Value, JsonError> Value::parse(const std::string& json) {
    cJSON* parsed = cJSON_Parse(json.c_str());
    if (!parsed) {
        const char* error_ptr = cJSON_GetErrorPtr();
        size_t position = error_ptr ? (error_ptr - json.c_str()) : 0;
        return expected<Value, JsonError>(JsonError(JsonErrorType::ParseError, "Failed to parse JSON", position));
    }
    return Value(parsed, true);
}

expected<Value, JsonError> Value::parse(const char* data, size_t size) {
    std::string json(data, size);
    return parse(json);
}

std::string Value::serialize() const {
    if (!cJSON_) return "null";

    char* serialized = cJSON_Print(cJSON_);
    if (!serialized) return "null";

    std::string result(serialized);
    cJSON_free(serialized);
    return result;
}

std::string Value::serialize_pretty(int /*indent*/) const {
    if (!cJSON_) return "null";

    char* serialized = cJSON_Print(cJSON_);
    if (!serialized) return "null";

    std::string result(serialized);
    cJSON_free(serialized);
    return result;
}

// Comparison
bool Value::operator==(const Value& other) const {
    if (!cJSON_ || !other.cJSON_) return cJSON_ == other.cJSON_;
    return cJSON_Compare(cJSON_, other.cJSON_, 1) == 1;
}

bool Value::operator!=(const Value& other) const {
    return !(*this == other);
}

// Schema implementation
struct Schema::Impl {
    // Simple implementation for now
};

Schema::Schema() : impl_(nullptr) {}

Schema::~Schema() {
    // Simple implementation - no actual schema validation for now
}

Schema& Schema::type(ValueType /*type*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::type(const std::string& /*custom_type*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::property(const std::string& /*name*/, Schema /*schema*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::required(const std::vector<std::string>& /*properties*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::description(const std::string& /*description*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::default_value(const Value& /*value*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::enum_values(const std::vector<Value>& /*values*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::minimum(double /*min*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::maximum(double /*max*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::min_length(size_t /*length*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::max_length(size_t /*length*/) {
    // TODO: Implement
    return *this;
}

Schema& Schema::pattern(const std::string& /*regex*/) {
    // TODO: Implement
    return *this;
}

Value Schema::to_json() const {
    // TODO: Implement
    return Value();
}

Schema Schema::from_json(const Value& /*json*/) {
    // TODO: Implement
    return Schema();
}

ValidationResult Schema::validate(const Value& /*value*/) const {
    // TODO: Implement proper validation
    return ValidationResult{true, {}};
}

// Copy and move for Schema
Schema::Schema(const Schema& /*other*/) : impl_(nullptr) {}

Schema::Schema(Schema&& other) noexcept : impl_(std::move(other.impl_)) {
    other.impl_ = nullptr;
}

Schema& Schema::operator=(const Schema& other) {
    if (this != &other) {
        // Simple implementation
    }
    return *this;
}

Schema& Schema::operator=(Schema&& other) noexcept {
    if (this != &other) {
        impl_ = std::move(other.impl_);
        other.impl_ = nullptr;
    }
    return *this;
}

} // namespace json
} // namespace mcp